package com.amumu.drama.common.modules.order.service.impl;

import cn.hutool.core.util.StrUtil;
import com.amumu.drama.common.config.PayConfig;
import com.amumu.drama.common.constant.*;
import com.amumu.drama.common.exception.Asserts;
import com.amumu.drama.common.modules.delivery.service.DeliveryService;
import com.amumu.drama.common.modules.member.service.UmsMemberService;
import com.amumu.drama.common.modules.order.dao.PortalOrderDao;
import com.amumu.drama.common.modules.order.dto.OmsOrderDetail;
import com.amumu.drama.common.modules.order.dto.PrePayCreateDTO;
import com.amumu.drama.common.modules.order.dto.PrePayInfoDTO;
import com.amumu.drama.common.modules.order.dto.req.PrePaymentReq;
import com.amumu.drama.common.modules.order.dto.req.QueryPayStatusReq;
import com.amumu.drama.common.modules.order.dto.resp.PayStatusResp;
import com.amumu.drama.common.modules.order.dto.resp.PrePaymentResp;
import com.amumu.drama.common.modules.order.manager.OrderManager;
import com.amumu.drama.common.modules.order.service.OmsPortalOrderService;
import com.amumu.drama.common.modules.order.service.PaymentService;
import com.amumu.drama.common.modules.service.impl.payment.PaymentFactory;
import com.amumu.drama.common.modules.service.impl.payment.PaymentReq;
import com.amumu.drama.common.modules.service.impl.payment.PaymentResp;
import com.amumu.drama.common.modules.service.impl.payment.handler.PaymentHandler;
import com.amumu.drama.mapper.OmsOrderMapper;
import com.amumu.drama.model.OmsOrder;
import com.amumu.drama.model.OmsOrderItem;
import com.amumu.drama.model.UmsMember;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class PaymentServiceImpl implements PaymentService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Autowired
    private PaymentFactory paymentFactory;
    @Autowired
    private OmsPortalOrderService omsPortalOrderService;
    @Autowired
    private OmsOrderMapper omsOrderMapper;

    @Autowired
    private UmsMemberService memberService;
    @Autowired
    private PayConfig payConfig;

    @Autowired
    private OrderManager orderManager;

    @Autowired
    private DeliveryService deliveryService;

    @Autowired
    private PortalOrderDao portalOrderDao;

    /**
     * 创建预支付订单
     *
     * @param request
     */
    @Override
    public PrePaymentResp prePayment(PrePaymentReq request) {
        PrePaymentResp resp = new PrePaymentResp();
        if (request == null || request.getOrderId() == null) {
            LOGGER.error("创建预支付订单请求参数错误:订单ID为空,request:{}", request);
            Asserts.fail("创建预支付订单请求参数错误:订单ID为空");
        }
        //查询订单信息 并判断订单状态是否为待支付
        OmsOrderDetail orderDetail = omsPortalOrderService.detail(request.getOrderId());
        if (orderDetail == null) {
            LOGGER.error("orderDetail {} not exist", request.getOrderId());
            Asserts.fail("订单不存在");
        }
        if (orderDetail.getPayStatus() != 0) {
            LOGGER.error("order {} status {} invalid", orderDetail.getId(), orderDetail.getStatus());
            Asserts.fail("订单状态不正确,无法支付");
        }
        PaymentHandler paymentHandler = paymentFactory.getPaymentHandlerByOrder(orderDetail);
        PrePayCreateDTO prePayCreateDTO = new PrePayCreateDTO();
        prePayCreateDTO.setOrderDetail(orderDetail);
        PrePayInfoDTO prePayInfoDTO = paymentHandler.prePay(prePayCreateDTO);
        resp.setPrePayInfoDTO(prePayInfoDTO);
        return resp;
    }

    /**
     * 轮询查询订单支付状态
     *
     * @param request
     */
    @Override
    public PayStatusResp queryPayStatus(QueryPayStatusReq request, OperateTypeEnum operateTypeEnum, Long operatorId) {
        if (request.getOrderId() == null) {
            Asserts.fail("订单ID为空");
        }
        OmsOrderDetail orderDetail = omsPortalOrderService.detail(request.getOrderId());
        if (orderDetail == null) {
            log.error("orderDetail {} not exist", request.getOrderId());
            Asserts.fail("订单不存在");
        }
        PayStatusResp resp = new PayStatusResp();
        if (!Objects.equals(PayStatusEnum.PAYING.getCode(), orderDetail.getPayStatus())) {
            resp.setPayStatus(orderDetail.getPayStatus());
            return resp;
        }
        //轮询向第三方查询订单的支付装套
        PaymentHandler paymentHandler = paymentFactory.getPaymentHandlerByOrder(orderDetail);
        PaymentResp paymentResp = paymentHandler.queryPayStatus(orderDetail);
        if (paymentResp.getOrderDetail() == null) {
            paymentResp.setOrderDetail(orderDetail);
        }
        if (paymentResp.getUmsMember() == null) {
            UmsMember member = memberService.getById(orderDetail.getMemberId());
            paymentResp.setUmsMember(member);
        }
        //更改订单状态
        orderManager.updateOrderPayStatus(request.getOrderId(), paymentResp, operateTypeEnum, operatorId == null ? orderDetail.getMemberId() : operatorId);
        LOGGER.info("payment response {}", paymentResp);
        resp.setPayStatus(paymentResp.getPayStatusEnum().getCode());
        return resp;
    }

    /** 支付接口 */
    @Override
    public PaymentResp pay(UmsMember umsMember, PaymentReq paymentReq) {
        if (paymentReq == null || paymentReq.getOrderId() == null) {
            LOGGER.error("支付请求参数错误:订单ID为空,paymentRequest:{}", paymentReq);
            Asserts.fail("支付请求参数错误:订单ID为空");
        }
        OmsOrderDetail orderDetail = orderManager.getOmsOrderDetailHighly(paymentReq.getOrderDetail(), paymentReq.getOrderId(), null, null);
        if (orderDetail == null) {
            LOGGER.error("orderDetail {} not exist", paymentReq.getOrderId());
            Asserts.fail("订单不存在");
        }
        if (!(Objects.equals(PayStatusEnum.WAIT_PAY.getCode(), orderDetail.getPayStatus()) || Objects.equals(PayStatusEnum.PAYING.getCode(), orderDetail.getPayStatus()))) {
            LOGGER.error("order {} status {} invalid", orderDetail.getId(), orderDetail.getStatus());
            Asserts.fail("订单状态不正确,无法支付");
        }
        paymentReq.setOrderDetail(orderDetail);
        OmsOrderItem orderItem = orderDetail.getOrderItemList().get(0);
        paymentReq.setUmsMember(umsMember);
        paymentReq.setPayAmount(orderDetail.getPayAmount());
        paymentReq.setSubject(orderItem.getProductName());
        paymentReq.setBody(orderItem.getProductName());
        LOGGER.info("payment request {}", paymentReq);
        PaymentHandler paymentHandler = paymentFactory.getPaymentHandlerByOrder(orderDetail);
        String payHandlerType = paymentHandler.getPayMethod(orderDetail);
        paymentReq.setNotifyUrl(payConfig.getNotifyUrl() + payHandlerType);
        PaymentResp paymentResp = paymentHandler.pay(paymentReq);
        if (paymentResp.getOrderDetail() == null) {
            paymentResp.setOrderDetail(orderDetail);
        }
        if (paymentResp.getUmsMember() == null) {
            paymentResp.setUmsMember(umsMember);
        }
        //更改订单状态
        orderManager.updateOrderPayStatus(paymentReq.getOrderId(), paymentResp, OperateTypeEnum.MEMBER, umsMember.getId());
        LOGGER.info("payment response {}", paymentResp);
        return paymentResp;
    }

    /**
     * 支付回调接口
     */
    @Override
    public String payNotify(String payHandlerType, Map<String, String> params, String body) {
        try {
            PaymentHandler paymentHandler = paymentFactory.getPaymentHandler(payHandlerType);
            PaymentResp paymentResp = paymentHandler.payNotify(params, body);
            if (paymentResp == null) {
                log.error("无通知接口实现");
                return null;
            }
            if (StrUtil.isBlank(paymentResp.getPayOrderSn())) {
                log.error("payOrderSn is null, payHandlerType:{} params:{},body:{}", payHandlerType, params, body);
                Asserts.fail("订单不存在");
            }
            OmsOrderDetail orderDetail = portalOrderDao.getDetailByPayOrderSn(paymentResp.getPayOrderSn());
            if (orderDetail == null) {
                log.error("orderDetail ：payOrderSn[{}] not exist", paymentResp.getPayOrderSn());
                Asserts.fail("订单不存在");
            }
            if (!Objects.equals(orderDetail.getPayStatus(), PayStatusEnum.PAYING.getCode())) {
                log.error("order {} status {} invalid", orderDetail.getId(), orderDetail.getStatus());
                Asserts.fail("订单状态不正确,无法支付");
            }
            paymentResp.setOrderDetail(orderDetail);
            //更改订单状态
            LOGGER.info("payment response {}", paymentResp);
            orderManager.updateOrderPayStatus(orderDetail.getId(), paymentResp, OperateTypeEnum.PAY_NOTIFY, orderDetail.getMemberId());
            return paymentResp.getRespMsg();
        } catch (Exception e) {
            LOGGER.error("pay notify error", e);
        }
        return OrderConstants.PAY_NOTIFY_RESP;
    }

    /**
     * 退款
     *
     * @param request todo 订单需要增加字段
     *                refund_order_sn 退款订单ID
     *                refund_amount 退款金额
     *                refund_apply_time 退款申请时间
     *                refund_finish_time 退款完成时间
     *                refund_reason  退款原因
     *                refund_msg 退款失败原因
     */
    @Override
    public PaymentResp refundApply(PaymentReq request, OperateTypeEnum operateTypeEnum, Long operatorId) {
        if (request == null || request.getOrderId() == null) {
            LOGGER.error("支付请求参数错误:订单ID为空,paymentRequest:{}", request);
            Asserts.fail("支付请求参数错误:订单ID为空");
        }
        OmsOrder omsOrder = omsOrderMapper.selectById(request.getOrderId());
        if (omsOrder == null) {
            LOGGER.error("omsOrder {} not exist", request.getOrderId());
            Asserts.fail("订单不存在");
        }
        if (!Objects.equals(omsOrder.getPayStatus(), PayStatusEnum.SUCCESS.getCode())) {
            LOGGER.error("order {} status {} invalid", omsOrder.getId(), omsOrder.getStatus());
            Asserts.fail("订单状态：" + PayStatusEnum.getByCode(omsOrder.getPayStatus()).getDesc() + ",无法退款");
        }
        PayTypeEnum payTypeEnum = PayTypeEnum.getByKey(omsOrder.getPayType());
        PaymentHandler paymentHandler = paymentFactory.getPaymentHandlerByOrder(omsOrder);
        String payHandlerType = paymentHandler.getPayMethod(omsOrder);
        PaymentReq paymentRequest = new PaymentReq();
        paymentRequest.setOmsOrder(omsOrder);
        paymentRequest.setRefundNotifyUrl(payConfig.getRefundNotifyUrl() + payHandlerType);
        paymentRequest.setOrderId(omsOrder.getId());
        paymentRequest.setPayTypeEnum(payTypeEnum);
        paymentRequest.setSourceTypeEnum(SourceTypeEnum.getByCode(omsOrder.getSourceType()));
        PaymentResp paymentResp = paymentHandler.refund(paymentRequest, operateTypeEnum, operatorId);
        paymentResp.setRefundReason(request.getRefundReason());
        orderManager.updateOrderPayStatus(omsOrder.getId(), paymentResp, operateTypeEnum, operatorId);
        return paymentResp;
    }

    /**
     * 退款回调通知
     *
     * @param payHandlerType
     * @param params
     * @param body
     */
    @Override
    public Object refundNotify(String payHandlerType, Map<String, String> params, String body) {
        try {
            PaymentHandler paymentHandler = paymentFactory.getPaymentHandler(payHandlerType);
            PaymentResp paymentResp = paymentHandler.payNotify(params, body);
            if (paymentResp == null) {
                log.error("支付退款接口回调：无通知接口实现，payHandlerType:[{}]", payHandlerType);
                return null;
            }
            if (StrUtil.isBlank(paymentResp.getPayOrderSn())) {
                log.error("支付退款接口回调：payOrderSn is null, payHandlerType:{} params:{},body:{}", payHandlerType, params, body);
                Asserts.fail("订单不存在");
            }

            OmsOrderDetail orderDetail = portalOrderDao.getDetailByPayOrderSn(paymentResp.getPayOrderSn());
            if (orderDetail == null) {
                log.error("支付退款接口回调：orderDetail ：payOrderSn[{}] not exist", paymentResp.getPayOrderSn());
                Asserts.fail("订单不存在");
            }
            if (!Objects.equals(orderDetail.getPayStatus(), PayStatusEnum.REFUNDING.getCode())) {
                log.error("支付退款接口回调：订单状态异常，order {} status {}，payStatus:[{}] invalid", orderDetail.getId(), orderDetail.getStatus(), orderDetail.getPayStatus());
                Asserts.fail("订单状态不在退款中,无法执行");
            }
            paymentResp.setOrderDetail(orderDetail);
            //更改订单状态
            LOGGER.info("支付退款接口回调响应题详情：payment response {}", paymentResp);
            orderManager.updateOrderPayStatus(orderDetail.getId(), paymentResp, OperateTypeEnum.REFUND_NOTIFY, orderDetail.getMemberId());
            return paymentResp.getRespMsg();
        } catch (Exception e) {
            LOGGER.error("支付退款接口回调异常 refund notify error", e);
        }
        return OrderConstants.PAY_NOTIFY_RESP;
    }

    /**
     * 轮询查询退款订单状态
     *
     * @param request
     * @param operateTypeEnum
     * @param operatorId
     */
    @Override
    public PaymentResp queryRefundStatus(QueryPayStatusReq request, OperateTypeEnum operateTypeEnum, Long operatorId) {
        if (request.getOrderId() == null) {
            Asserts.fail("查询订单退款状态：订单ID为空");
        }
        OmsOrderDetail orderDetail = omsPortalOrderService.detail(request.getOrderId());
        if (orderDetail == null) {
            log.error("查询订单退款状态：orderId:[{}],orderDetail {} not exist", request.getOrderId(), orderDetail);
            Asserts.fail("订单不存在");
        }
        PaymentResp resp = new PaymentResp();
        if (!Objects.equals(PayStatusEnum.REFUNDING.getCode(), orderDetail.getPayStatus())) {
            resp.setPayStatusEnum(PayStatusEnum.getByCode(orderDetail.getPayStatus()));
            resp.setOrderDetail(orderDetail);
            return resp;
        }
        //轮询向第三方查询订单的支付装套
        PaymentHandler paymentHandler = paymentFactory.getPaymentHandlerByOrder(orderDetail);
        PaymentResp paymentResp = paymentHandler.queryPayStatus(orderDetail);
        //更改订单状态
        orderManager.updateOrderPayStatus(request.getOrderId(), paymentResp, operateTypeEnum, operatorId == null ? orderDetail.getMemberId() : operatorId);
        LOGGER.info("查询订单退款状态：orderId;{},payment response {}", request.getOrderId(), paymentResp);
        return paymentResp;
    }
}
